﻿#define _CRT_SECURE_NO_WARNINGS 1

//#include"Date.h"
//
//class Stack
//{
//public:
//	Stack(int capacity = 4)
//	{
//
//	}
//private:
//	int* _arr;
//	int _capacity;
//	int _size;
//};
//
//class MyQueue
//{
//public:
//	//编译器默认生成MyQueue的构造函数调用了Stack的默认构造,
//	//完成了两个成员的初始化
//	//如果栈没有默认构造,那么就得显示的调用它的构造
//	//MyQueue()
//	//{
//	//	_pushst(1);//这样调是不支持的
//	//}
//	/*****************************************************/
//	//MyQueue()//这个时候就必须使用初始化列表初始化的调用了
//	//	:_pushst(10)
//	//	,_popst(10)
//	//{
//
//	//}
//	/*****************************************************/
//	//如果想控制栈的大小,就可以加个参数
//	MyQueue(int& r,int n = 10)
//		:_pushst(n)
//		,_popst(n)
//		,_y(1)
//		,_z(r)
//	{
//		_x = 1;
//	}
//private:
//	Stack _pushst;
//	Stack _popst;
//	int _x;
//	const int _y;
//	int& _z;
//};
//
//
//int main()
//{
//	Date d1(2004,2,5);
//	Date d2(2024, 8, 10);
//	int index = d1 - d2;
//	cout << index << endl;
//
//
//	/*cin >> d1 >> d2;
//	cout << d1 << d2 << endl;*/
//
//	Date d(2023, 2, 22);
//	d.Print();
//
//	return 0;
//

//#include<iostream>
//using namespace std;
//class Time
//{
//public:
//	Time(int hour)
//		:_hour(hour)
//	{
//		cout << "Time()" << endl;
//	}
//private:
//	int _hour;
//};
//class Date
//{
//public:
//	Date()
//		:_month(2)
//	{
//		cout << "Date()" << endl;
//	}
//	void Print() const
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//private:
//	// 注意这⾥不是初始化，这⾥给的是缺省值，这个缺省值是给初始化列表的
//	// 如果初始化列表没有显⽰初始化，默认就会⽤这个缺省值初始化
//	int _year = 1;
//	int _month = 1;
//	int _day;
//	Time _t = 1;
//	const int _n = 1;
//	int* _ptr = (int*)malloc(12);
//};
//int main()
//{
//	Date d1;
//	d1.Print();
//	return 0;
//}

//#include <iostream>
//using namespace std;
//class A
//{
//public:
//	A(int a)
//		:_a1(a)
//		, _a2(_a1)
//	{}
//	void Print()
//	{
//		cout << _a1 << " " << _a2 << endl;
//	}
//private:
//	int _a2 = 2;
//	int _a1 = 2;
//};
//int main()
//{
//	A aa(1);
//	aa.Print();
//}

//#include<iostream>
//using namespace std;
//class A
//{
//public:
//	// 构造函数explicit就不再⽀持隐式类型转换
//	// explicit A(int a1)
//    A(int a1)//加上explicit之后这里的整型就不能转换成a这个类型了
//		:_a1(a1)
//	{
//        cout << " A(int a1) " << endl;
//    }
//	//explicit A(int a1, int a2)
//	A(int a1, int a2)//多参数的构造函数
//		:_a1(a1)
//		, _a2(a2)
//	{}
//
//    //拷贝构造
//    A(const A& aa)
//        :_a1(aa._a1)
//        ,_a2(aa._a2)
//    {
//        cout << " A(const A& aa) " << endl;
//    }
//	void Print()
//	{
//		cout << _a1 << " " << _a2 << endl;
//	}
//    int Get() const
//    {
//        return _a1 + _a2;
//    }
//private:
//    int _a1 = 1;
//    int _a2 = 2;
//};
//class B
//{
//public:
//    B(const A& a)
//        :_b(a.Get())
//    {}
//private:
//    int _b = 0;
//};
//
////有一个栈,这个栈存储的数据是A类型的
//class Stack
//{
//public:
//    void Push(const A& a)//加引用,形参传给实参的话就没有拷贝了
//    {}
////........
//};
//
//int main()
//{
//    //用栈存储A类型的数据
//    //方式1 - 定义一个对象,在用这个对象去传参
//    Stack st;
//    A _a1(1);
//    st.Push(_a1);
//
//    A _a2{ 1, 2 };
//    st.Push(_a2);
//    //方式2 - 有隐式类型转换的支持,写起来就很方便
//    st.Push(3);
//    st.Push({ 1, 2 });
//    //隐式类型转换,C++支持这个东西本质是为了A这种自定义类型要传参等操作
//    //的话就会更方便，不用定义对象,在push这个对象了。
//
//    // 1构造⼀个A的临时对象，再⽤这个临时对象拷贝构造aa3
//    // 编译器遇到连续构造+拷贝构造->优化为直接构造
//    /*A aa1 = 1;
//    aa1.Print();*/
//    
//    //const A& aa2 = 1;
//    //这里的引用,不是引用的1,而是引用的临时对象,但是这只有一个构造,没有
//    //拷贝构造,是不会优化的,这种临时对象具有常性,就像被const修饰一样,所以
//    //前面要加上const
//
//    //C++11之后才支持多参数转化
//    A aa3 = { 2,2 };//这样写调用的是多参数的
//    //A aa3 = (2, 2);//这样写本质还是调的单参数的,因为里面是逗号表达式
//    //const A& aa4 = { 1,1 };//引用的是临时对象,随意要加const
//
//    //aa3隐式类型转换为b对象原理跟上面类似
//    B b = aa3;
//    const B& rb = aa3;
//    return 0;
//}
/*
这里的1是可以给aa1的,本质就是支持隐式类型转换,因为1是整型,有构造
的支持,1这个整型可以构造一个a,所以1先构造了一个A的临时对象。
临时对象:编译器开了一块空间进行存储,但是这块空间没有名字,这叫临时对象(匿名对象)
然后再用这个地方的临时对象拷贝构造,但是编译器在这里不会走临时对象
然后再走拷贝构造,因为编译器会在这优化,因为用1构造了一个临时对象,
类型转换中间会产生临时对象,用1构造临时对象,再用临时对象拷贝构造,
编译器觉得构造,再拷贝构造太浪费了,所以编译器会把这种连续的构造直接
优化成构造,合二为一了,所以打印结果就是直接调用构造,步调拷贝构造

而且初始化列表中只初始化了_a,没有初始化_a2,所以_a2使用的是缺省值
*/

/*
int i = 10;
double d = i;
//double& rd = i;//err,报错原因不是因为类型不同,因为int给double中间会产生临时对象
const double& rd = i;//临时对象具有常性,所以前面加上double就可以了
*/


// 实现⼀个类，计算程序中创建出了多少个类对象？
//#include<iostream>
//using namespace std;
//class A
//{
//public:
//	A()
//	{
//		++_scount;
//	}
//	A(const A& t)
//	{
//		++_scount;
//	}
//	~A()//如果相要看占用内存的对象,那么在析构中--_scount就可以了
//	{
//		--_scount;
//	}
//	static int GetACount()//如果_scount是私有的,那么就得写个成员函数返回_scount
//	{
//		return _scount;
//		//_i = 1;//非静态的不能访问
//	}
//private:
//	//类里面声明
//	static int _scount;
//	//static int _scount = 3;
//	//不能给缺省值,因为缺省值是给初始化列表的,静态的成员变量
//	//不会走初始化列表
//
//	int _i = 0;//非静态成员变量
//};
////类外面初始化
//int A::_scount = 0;
//void Func(A aa)
//{}
//void Fxx()
//{
//	//A aa3;//创建这个对象是专门为了调用GetACount函数而创建的,所有打印的时候必须-1。
//	//cout << aa3.GetACount() - 1 << endl;
//	//那么也可以不创建对象调用 - 那么就得用到static修饰
//	//静态的不能方位非静态的,非静态的可以访问静态的
//	cout << A::GetACount() << endl;
//}
//int main()
//{
//	cout << A::GetACount() << endl;
//	A a1, a2;
//	A a3(a1);
//	Func(a1);
//	cout << A::GetACount() << endl;
//	cout << a1.GetACount() << endl;
//	Fxx();
//	//编译报错:error C2248 : “A::_scount” :无法访问private成员(在"A"类中声明)
//	//突破类域访问的两种方式
//	//cout << A::_scount << endl;
//	//cout << a1._scount << endl;
//	return 0;
//}

//#include <iostream>
//using namespace std;
//class Sum
//{
//public:
//    Sum()
//    {
//        _ret += _i;
//        _i++;
//    }
//    static int Getret()
//    {
//        return _ret;
//    }
//private:
//    static int _i;
//    static int _ret;
//};
//int Sum::_i = 1;
//int Sum::_ret = 0;
//
//int main()
//{
//    int n = 0;
//    cin >> n;
//    Sum* arr = new Sum[n];
//    //new这个东西其实就是构造一个n个数的数组,只是动态
//    //开辟,它会调用10次构造函数。
//    cout << Sum::Getret() << endl;
//    //释放
//    //.....
//    return 0;
//}
//#include <iostream>
//using namespace std;
//class A
//{
//public:
//	A()
//	{
//		cout << "A()" << endl;
//	}
//	~A()
//	{
//		cout << "~A()" << endl;
//	}
//};
//
//class B
//{
//public:
//	B()
//	{
//		cout << "B()" << endl;
//	}
//	~B()
//	{
//		cout << "~B()" << endl;
//	}
//};
//class C
//{
//public:
//	C()
//	{
//		cout << "C()" << endl;
//	}
//	~C()
//	{
//		cout << "~C()" << endl;
//	}
//};
//class D
//{
//public:
//	D()
//	{
//		cout << "D()" << endl;
//	}
//	~D()
//	{
//		cout << "~D()" << endl;
//	}
//};
//
//C c;
//int main()
//{
//	A a;
//	B b;
//	static D d;
//	return 0;
//}

//#include<iostream>
//using namespace std;
////前置声明,否则A的友元函数声明编译器不认识B
//class B;
//class A
//{
//	//友元声明
//	friend void func(const A& aa, const B& bb);
//private:
//	int _a1 = 1;
//	int _a2 = 2;
//};
//class B
//{
//	//友元声明
//	friend void func(const A& aa, const B& bb);
//private:
//	int _b1 = 3;
//	int _b2 = 4;
//};
//void func(const A& aa, const B& bb)
//{
//	cout << aa._a1 << endl;
//	cout << bb._b1 << endl;
//}
//int main()
//{
//	A aa;
//	B bb;
//	func(aa, bb);
//	return 0;
//}

//#include<iostream>
//using namespace std;
//class A
//{
//	//友元声明
//	friend class B;//不加友元func1和func2都无法访问
//private:
//	int _a1 = 1;
//	int _a2 = 2;
//};
//class B
//{
//public:
//	void func1(const A& aa)
//	{
//		cout << aa._a1 << endl;
//		cout << _b1 << endl;
//	}
//	void func2(const A& aa)
//	{
//		cout << aa._a2 << endl;
//		cout << _b2 << endl;
//	}
//private:
//	int _b1 = 3;
//	int _b2 = 4;
//};
//int main()
//{
//	A aa;
//	B bb;
//	bb.func1(aa);
//	bb.func1(aa);
//	return 0;
//}

//#include<iostream>
//using namespace std;
//class A
//{
//private:
//    static int _k;
//    int _h = 1;
//public:
//    class B //B默认就是A的友元
//    {
//    public:
//        void foo(const A& a)
//        {
//            cout << _k << endl;//因为B是A的友元,所以可以访问私有的变量
//            cout << a._h << endl;//OK
//        }
//    private:
//        int _b;
//    };
//};
//int A::_k = 1;
//int main()
//{
//    cout << sizeof(A) << endl;
//    /*
//    sizeof(A)的大小是4个字节,首先_k这个静态成员变量肯定
//    不用计算,因为静态成员变量没有存储在对象中,单独存储在
//    静态区。
//    B类里面的_b这个整型也不需要计算,这说明A对象里面没有
//    这个B对象,内部类并不是说B变成A的成员,A是A,B是B,B定义
//    在A的里面只是说B这个类受到A这个类的类域的限制,B的成员
//    并不会变成A的一部分m。
//    */
//
//    //B b;//err
//    A::B b;//访问B这个类不能直接访问,受类域的限制,得指定类域
//    //还受到访问限定符的限制,如果改成私有,就访问不了了。
//
//    A aa;
//    b.foo(aa);
//    return 0;
//}

//#include <iostream>
//using namespace std;
//class A
//{
//public:
//    A(int a = 0)
//        :_a(a)
//    {
//        cout << "A(int a)" << endl;
//    }
//    ~A()
//    {
//        cout << "~A()" << endl;
//    }
//private:
//    int _a;
//};
//class Solution {
//public:
//    int Sum_Solution(int n) {
//        //...
//        return n;
//    }
//};
////自定义类型给缺省参数比较好的写法就是给匿名对象
//void func(A aa = A(1))
//{ }
//int main()
//{
//    A aa1(1);//有名对象 - 有名字的对象
//    A aa2;
//
//    A(1);//匿名对象
//    A();
//    /*
//    匿名对象的特点就是相比有名对象的生命周期短,
//    有名对象的生命周期在当前的块作用域,aa1和aa2
//    的析构是在main函数结束以后。
//    匿名对象的特点就是他的生命周期在当前这一行
//    其次需要注意的就是有名对象有参数的时候后面就
//    加括号,传参,没有参数的时候不需要加括号,但是
//    匿名对象的话没有参数不可能只写个类型,所以匿名
//    没有参数的时候后面还得加括号。
//    */
//
//    //匿名对象的使用场景
//    //之前使用有名对象调用Sum_Solution函数的话得写成两行
//    Solution s1;
//    cout << s1.Sum_Solution(10) << endl;
//    //使用匿名对象调用Sum_Solution函数
//    cout << Solution().Sum_Solution(10) << endl;
//
//    func();
//
//    //匿名对象是可以引用的,匿名对象跟临时对象一样,具有常性
//    //所以要加const,但是加上const有一个不一样的就是const
//    //引用会延长匿名对象的生命周期,其实临时对象也会被延长。
//    //具体延长的啥时候就跟着这个引用走。
//    // 如果不延长生命周期的话,该引用就会变成野引用。
//    const A& r = A();
//    return 0;
//}


//#include<iostream>
//using namespace std;
//class A
//{
//public:
//    A(int a = 0)
//        :_a1(a)
//    {
//        cout << "A(int a)" << endl;
//    }
//    A(const A& aa)
//        :_a1(aa._a1)
//    {
//        cout << "A(const A& aa)" << endl;
//    }
//    A& operator=(const A& aa)
//    {
//        cout << "A& operator=(const A& aa)" << endl;
//        if (this != &aa)
//        {
//            _a1 = aa._a1;
//        }
//        return *this;
//    }
//    ~A()
//    {
//        cout << "~A()" << endl;
//    }
//private:
//    int _a1 = 1;
//};
//void f1(A aa)
//{}
//A f2()//传值返回还要调用拷贝构造,这里不能引用返回,因为aa是局部对象
//{
//    A aa;
//    return aa;
//}
//int main()
//{
//    A aa1 = 1;
//
//    f2();
//    /*
//    这里返回不能返回aa,因为aa是局部对象,返回的话就成
//    野引用了,所以这个时候中间会生成一个临时对象,这个
//    临时对象作为返回值,先构造,再拷贝构造,这个拷贝构造
//    就是去生成临时对象,(vs2019上不做优化)
//    */
//    cout << endl;
//
//    A aa2 = f2();
//    cout << endl;
//
//    aa1 = f2();
//    cout << endl;
//
//    return 0;
//}


//int main()
//{
//    //优化
//    A aa1 = 1;
//    cout << endl;
//    /*
//    内置类型要想转换成自定义类型就必须依靠构造函数
//    语法上是用1去构造一个A的临时对象,再用临时对象去拷贝构造,
//    但是从结果上来说我们看到的并不是构造+拷贝构造,而是直接构造
//    因为编译器优化了,构造+拷贝构造编译器觉得太浪费了,直接构造也
//    不会有其他的问题。优化的前提是跟不优化达到的效果必须是一样的。
//    */
//    
//    //传值传参优化
//    A aa2;
//    f1(aa2);
//    cout << endl;
//    /*
//    先调用构造函数,传参的时候调用拷贝构造,然后就析构,析构
//    的是aa,aa是属于形参,f1函数调用结束以后,aa就销毁了,这个
//    位置暂且没有优化
//    */
//
//    //隐式类型、连续构造+拷贝构造->优化为直接构造
//    f1(1);
//    /*
//    本来的话这里要用1去构造临时对象A,然后再用临时对象去拷贝
//    构造aa。优化成了直接构造
//    */
//
//    //一个表达式中,连续构造+拷贝构造->优化为一个构造。
//    f1(A(2));
//    cout << endl;
//    /*
//    语法的语义上面构造一个匿名对象,再用这个匿名对象传值
//    传参给函数,这是拷贝构造,这里也是构造+拷贝构造,但是实际
//    还是直接构造,编译器优化为直接构造。
//    */
//
//    cout << "###############################" << endl;
//
//    return 0;
//}

//int main()
//{
//    // 传值传参
//    A aa1;
//    f1(aa1);
//    cout << endl;
//    //隐式类型，连续构造+拷⻉构造->优化为直接构造
//
//    f1(1);
//    //⼀个表达式中，连续构造+拷⻉构造->优化为⼀个构造
//
//    f1(A(2));
//    cout << endl;
//    cout << "***********************************************" << endl;
//    // 传值返回
//
//    //返回时⼀个表达式中，连续拷⻉构造+拷⻉构造->优化⼀个拷⻉构造（vs2019 debug）
//
//    // ⼀些编译器会优化得更厉害，进⾏跨⾏合并优化，直接变为构造。（vs2022 debug）
//
//    f2();
//    cout << endl;
//    //返回时⼀个表达式中，连续拷⻉构造+拷⻉构造->优化⼀个拷⻉构造（vs2019 debug）
//
//    // ⼀些编译器会优化得更厉害，进⾏跨⾏合并优化，直接变为构造。（vs2022 debug）
//
//    A aa2 = f2();
//    cout << endl;
//    //⼀个表达式中，连续拷⻉构造+赋值重载->⽆法优化
//
//    aa1 = f2();
//    cout << endl;
//    return 0;
//}


#include<iostream>
using namespace std;
class A
{
public:
    A(int a = 0)
        :_a1(a)
    {
        cout << "A(int a)" << endl;
    }
    A(const A& aa)
        :_a1(aa._a1)
    {
        cout << "A(const A& aa)" << endl;
    }
    A& operator=(const A& aa)
    {
        cout << "A& operator=(const A& aa)" << endl;
        if (this != &aa)
        {
            _a1 = aa._a1;
        }
        return *this;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }
private:
    int _a1 = 1;
};
void f1(A aa)
{}
A f2()
{
    A aa;
    return aa;
}
int main()
{
    A aa1 = 1;

    f2();
    cout << endl;

    A aa2 = f2();
    cout << endl;

    aa1 = f2();
    cout << endl;

    return 0;
}

